﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using NoDriverPrintHelperV1d0.Entity;
using ZhangLogSysV1d0;
using System.Threading;
using NoDriverPrintHelperV1d0.Service;

namespace NoDriverPrintHelperV1d0.ControlUi
{
    /// <summary>
    /// 打印管理控制控件
    /// </summary>
    public partial class ControlPrinterManageV1d0 : UserControl
    {
        public ControlPrinterManageV1d0()
        {
            InitializeComponent();
            PrinterIp = "192.168.3.99";
            PrinterPort = 9100;
            PrinterTcpClient = null;
            PrinterStatus = 0;
            ConnectStatus = 0;
            IsPrinterReady = false;
            
        }

        /// <summary>
        /// 开始运行
        /// </summary>
        public void StartRunning()
        {
            SettingStatusBarInMainThread(IsPrinterReady);            
            //开始心跳检测
            StartPulseCheck();
            //开始任务处理
            StartTaskProcess();
            TcpConnectThread = new ThreadTcpClientConnectV1d0();
            int i = 10;
            TcpConnectThread.Thread_index = i;
            TcpConnectThread.PrinterPort=9100;// textBoxIp.Text;// "192.168.1.186";
            TcpConnectThread.PrinterIp="192.168.3.99";
            TcpConnectThread.ConnectedReadyEvent += ProcConnectedReadyEvent;
            TcpConnectThread.IsDisconnected = true;
            TcpConnectThread.StartThread();
        }
        public void StopRunning()
        {
            myTimerPulseCheck = null;
            myTimerProcessTask = null;
            PulseCheckTimer = null;
            TcpConnectThread.StopThread();
            DisconnectToPrinter();
        }
        public string PrinterIp { get; set; }
        public int PrinterPort { get; set; }
        public static byte[] ByteMessage = new byte[1024];
        public TcpClient PrinterTcpClient = null;
        ThreadTcpClientConnectV1d0 TcpConnectThread = null;
        public ManualResetEvent PulseCheckTimeoutObject = new ManualResetEvent(false);
        public TmU220EscPosPrintFunctionV1d0 WorkingPrinter = null;
        System.Threading.Timer myTimerPulseCheck = null;
        System.Threading.Timer myTimerProcessTask = null;

        System.Threading.Timer PulseCheckTimer { get; set; }
        /// <summary>
        /// 网络连接状态
        /// </summary>
        private int _ConnectStatus;
        public int ConnectStatus
        {
            get
            {
                lock (LockConnectStatus)
                {
                    return _ConnectStatus;
                }
            }
            set
            {
                lock (LockConnectStatus)
                {
                    _ConnectStatus = value;
                }
            }
        }
        private static object LockConnectStatus = new object();

        /// <summary>
        /// 打印机状态
        /// </summary>
        private int _PrinterStatus;
        public int PrinterStatus
        {
            get
            {
                lock (LockPrinterStatus)
                {
                    return _PrinterStatus;
                }
            }
            set
            {
                lock (LockPrinterStatus)
                {
                    _PrinterStatus = value;
                }
            }
        }

        private static object LockPrinterStatus = new object();
        /// <summary>
        /// 打印机是否可用
        /// </summary>
        private bool _IsPrinterReady;
        public bool IsPrinterReady
        {
            get
            {
                lock (LockIsPrinterReady)
                {
                    return _IsPrinterReady;
                }
            }
            set
            {
                lock (LockIsPrinterReady)
                {
                    _IsPrinterReady = value;
                }
            }
        }
        private static object LockIsPrinterReady = new object();

        /// <summary>
        /// 已接收任务列表
        /// </summary>
        public static object LockReceivedTaskList = new object();
        public List<PrintTaskV1d0> ReceivedTaskList = new List<PrintTaskV1d0>();
        public long CurrTaskIndex = -1;
        public void ProcConnectedReadyEvent(object sender, TcpClient printeTcpClient)
        {
            PrinterTcpClient = printeTcpClient;
            InitPrinter();
            IsPrinterReady = true;
            SettingStatusBarInMainThread(IsPrinterReady);
            MessageBox.Show("打印机连接正常");
        }
        /// <summary>
        /// 打印完成任务列表
        /// </summary>
        public List<PrintTaskV1d0> PrinteCompleteTaskList = new List<PrintTaskV1d0>();
        /// <summary>
        /// 打印错误任务列表
        /// </summary>
        public List<PrintTaskV1d0> PrinteErrorTaskList = new List<PrintTaskV1d0>();
        /// <summary>
        /// 用打印任务列表,更新指定ListBox
        /// </summary>
        /// <param name="listBox"></param>
        /// <param name="taskList"></param>
        public void UpdateListBox(ListBox listBox, List<PrintTaskV1d0> taskList)
        {
            this.Invoke(new Action(() =>
            {
                listBox.Items.Clear();
                foreach (var task in taskList)
                {
                    listBox.Items.Add(task.create_time.ToString("HH-mm-ss-ffff"));
                }
            }));
        }
        /// <summary>
        /// 查询服务器打印任务数据表中，任务序号大于序号值的所有的打印任务
        /// </summary>
        /// <param name="taskIndexMin">任务序号最小值</param>
        /// <returns>打印任务列表</returns>
        public List<PrintTaskV1d0> GetPrintTaskFromServer(long taskIndexMin)
        {
            List<PrintTaskV1d0> taskList = new List<PrintTaskV1d0>();
            PrintTaskV1d0 printTask1 = new PrintTaskV1d0();
            PrintTaskItemV1d0 prinTaskItem1 = new PrintTaskItemV1d0();
            prinTaskItem1.content_text = "1-abedefghijlk\n";
            prinTaskItem1.print_sequence = 0;
            PrintTaskItemV1d0 prinTaskItem2 = new PrintTaskItemV1d0();
            prinTaskItem2.content_text = "2-12345678\n";
            prinTaskItem2.print_sequence = 1;
            PrintTaskItemV1d0 prinTaskItem3 = new PrintTaskItemV1d0();
            prinTaskItem3.print_sequence = 2;
            prinTaskItem3.content_text = "3-abedefghijlk12345678\n";
            printTask1.task_index = 1;
            printTask1.PrintTaskItemList.Add(prinTaskItem1);
            printTask1.PrintTaskItemList.Add(prinTaskItem2);
            printTask1.PrintTaskItemList.Add(prinTaskItem3);

            PrintTaskV1d0 printTask2 = new PrintTaskV1d0();
            printTask2.task_index = 2;
            printTask2.PrintTaskItemList.Add(prinTaskItem1);
            printTask2.PrintTaskItemList.Add(prinTaskItem2);
            printTask2.PrintTaskItemList.Add(prinTaskItem3);

            PrintTaskV1d0 printTask3 = new PrintTaskV1d0();
            printTask3.task_index = 3;
            printTask3.PrintTaskItemList.Add(prinTaskItem1);
            printTask3.PrintTaskItemList.Add(prinTaskItem2);
            printTask3.PrintTaskItemList.Add(prinTaskItem3);

            PrintTaskV1d0 printTask4 = new PrintTaskV1d0();
            printTask4.task_index = 4;
            printTask4.PrintTaskItemList.Add(prinTaskItem1);
            printTask4.PrintTaskItemList.Add(prinTaskItem2);
            printTask4.PrintTaskItemList.Add(prinTaskItem3);

            taskList.Add(printTask1);
            //taskList.Add(printTask2);
            //taskList.Add(printTask3);
            //taskList.Add(printTask4);

            return taskList;
        }

        
        /// <summary>
        /// 连接到打印机
        /// </summary>
        /// <returns></returns>
        public bool ConnectToPrinter()
        {
            bool result = ConnectToPrinter(PrinterIp, PrinterPort);
            return result;
        }

        /// <summary>
        /// 在连接打印机成功后，初始化打印机
        /// </summary>
        /// <returns></returns>
        private bool InitPrinter()
        {
            bool result = false;
            try
            {
                if (PrinterTcpClient != null && PrinterTcpClient.Connected)
                {
                    ConnectStatus = 1;
                    //-------
                    WorkingPrinter = new TmU220EscPosPrintFunctionV1d0(PrinterTcpClient);
                    //初始化打印机
                    result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.init_printer());
                    //使能自动状态回复ASB
                    result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.enableAsb());
                    //请求打印机传输纸张状态
                    result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.transferPrinterStatus());

                    //数据接收控制
                    ByteMessage = new byte[PrinterTcpClient.ReceiveBufferSize];
                    NetworkStream netStream = PrinterTcpClient.GetStream();
                    if (netStream.CanRead)
                    {
                        //异步读取数据
                        netStream.BeginRead(ByteMessage, 0, ByteMessage.Length, new AsyncCallback(SocketAsyncReadCallBack), netStream);
                    }
                    result = true;
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            return result;
        }
        /// <summary>
        /// 连接到打印机
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <param name="port">端口</param>
        /// <returns>是否连接成功</returns>
        private bool ConnectToPrinter(string ip,int port)
        {
            bool result = false;
            try
            {
                if (PrinterTcpClient == null || (PrinterTcpClient != null && (!PrinterTcpClient.Connected)))
                {
                    //2秒的连接超时
                    PrinterTcpClient = TcpClientWithTimeoutV1d0.TryConnect(ip, port, 2000);
                    if (PrinterTcpClient != null && PrinterTcpClient.Connected)
                    {
                        ConnectStatus = 1;
                        //-------
                        WorkingPrinter = new TmU220EscPosPrintFunctionV1d0(PrinterTcpClient);
                        //初始化打印机
                        result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.init_printer());
                        //使能自动状态回复ASB
                        result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.enableAsb());
                        //请求打印机传输纸张状态
                        result = WorkingPrinter.SendByteCommand(PrinterCmdUtilsV1d0.transferPrinterStatus());

                        //数据接收控制
                        ByteMessage = new byte[PrinterTcpClient.ReceiveBufferSize];
                        NetworkStream netStream = PrinterTcpClient.GetStream();
                        if (netStream.CanRead)
                        {
                            //异步读取数据
                            netStream.BeginRead(ByteMessage, 0, ByteMessage.Length, new AsyncCallback(SocketAsyncReadCallBack), netStream);
                        }
                        result = true;
                    }
                    else result = false;
                }
                else if(PrinterTcpClient != null && (PrinterTcpClient.Connected))
                {
                    result = true;
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
                result = false;
            }
            return result;
        }
        public void DisconnectToPrinter()
        {
            if (PrinterTcpClient != null)
            {
                TcpConnectThread.ConnectedReadyEvent -= ProcConnectedReadyEvent;
                TcpConnectThread.StopThread();
                PrinterTcpClient.Close();
                PrinterTcpClient = null;
                myTimerPulseCheck.Dispose();
                myTimerPulseCheck.Dispose();
            }
        }

        public void SettingStatusBarInMainThread(bool isPrinterReady)
        {
            try
            {
                if (this.IsDisposed)
                    return;

                if (!this.InvokeRequired)
                {
                    SettingStatusBar(isPrinterReady);
                    return;
                }
                //MethodInvoker 需要无参数的函数，所以使用匿名委托将带参数的函数转换为不带参数的委托
                this.Invoke(
                    new MethodInvoker(
                        delegate ()
                        {
                            SettingStatusBar(isPrinterReady);
                        }
                    )
                );
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
        }
        /// <summary>
        /// 设置状态栏
        /// </summary>
        /// <param name="isPrinterReady"></param>
        public void SettingStatusBar(bool isPrinterReady)
        {            
            try
            {
                this.Invoke(new Action(() =>
                {
                    this.toolStripStatusLabelPinterInfo.Text = "打印机Ip:" + PrinterIp + " Port:" + PrinterPort.ToString();
                    this.toolStripStatusLabelPrinterIsReady.Text = isPrinterReady ? "打印机可用" : "打印机不可用";
                }));                
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
        }
        /// <summary>
        /// 套接字异步网络流读取的回调函数
        /// </summary>
        /// <param name="iAsyncResult"></param>
        public void SocketAsyncReadCallBack(IAsyncResult iAsyncResult)
        {
            try
            {
                NetworkStream nStreamRead = iAsyncResult.AsyncState as NetworkStream;
                int countOfBytesRead = nStreamRead.EndRead(iAsyncResult);
                if (countOfBytesRead > 0)
                {
                    byte[] buffer = new byte[countOfBytesRead];
                    Array.Copy(ByteMessage, 0, buffer, 0, countOfBytesRead);
                    //对读取到的数据进行处理
                    ProcessMessageInMainThread(buffer);
                    //继续进行下一次的异步读取,并将tcpClient套接字的网络数据流对象传递给回调函数
                    nStreamRead.BeginRead(ByteMessage, 0, ByteMessage.Length, new AsyncCallback(SocketAsyncReadCallBack), nStreamRead);
                }
                else
                {
                    nStreamRead.Close();
                    nStreamRead = null;
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
        }
        /// <summary>
        /// 在主线程刷新UI
        /// </summary>
        /// <param name="byteMessage"></param>
        public void ProcessMessageInMainThread(byte[] byteMessage)
        {
            try
            {
                if (this.IsDisposed)
                    return;

                if (!this.InvokeRequired)
                {
                    ProcessMessage(byteMessage);
                    return;
                }
                //MethodInvoker 需要无参数的函数，所以使用匿名委托将带参数的函数转换为不带参数的委托
                this.Invoke(
                    new MethodInvoker(
                        delegate ()
                        {
                            ProcessMessage(byteMessage);
                        }
                    )
                );
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
        }

        /// <summary>
        /// 处理接收到的消息
        /// </summary>
        /// <param name="byteMessage"></param>
        private void ProcessMessage(byte[] byteMessage)
        {
            try
            {
                string stringMessage = "打印机状态未知";
                if (byteMessage.Length == 1)
                {
                    //打印机连接正常
                    ConnectStatus = 1;
                    //进纸器状态
                    byte printerStatus = byteMessage[0];
                    if (printerStatus == 0)
                    {
                        stringMessage = "进纸器状态正常";
                        PrinterStatus = 1;
                    }
                    else if (printerStatus >= 3)
                    {
                        stringMessage = "打印纸将近末端";
                        PrinterStatus = 2;
                    }
                    else if (printerStatus >= 12)
                    {
                        stringMessage = "打印机缺纸";
                        PrinterStatus = -1;
                    }
                }
                else if (byteMessage.Length == 4)
                {
                    //打印机连接正常
                    ConnectStatus = 1;
                    RestoreRadioButtonsInMainThread();
                    byte printerStatus0 = byteMessage[0];
                    byte printerStatus1 = byteMessage[1];
                    byte printerStatus2 = byteMessage[2];
                    byte printerStatus3 = byteMessage[3];//暂不使用
                    if (printerStatus0 <= 20 & printerStatus1 == 0 && printerStatus2 == 0)
                    {
                        stringMessage = "打印机状态正常";
                        PrinterStatus = 1;
                    }
                    else
                    {
                        if (printerStatus0 == 32)
                        {
                            //按下走纸键
                            PrinterStatus = 4;
                        }
                        else
                        {
                            PrinterStatus = 1;
                        }

                        if (printerStatus1 >= 4)
                        {
                            //出现机械故障
                            PrinterStatus = -1;
                        }
                        if (printerStatus1 >= 8)
                        {
                            //出现裁纸器故障
                            PrinterStatus = -1;
                        }
                        if (printerStatus1 >= 32)
                        {
                            //出现不可恢复错误
                            PrinterStatus = -1;
                        }
                        if (printerStatus1 >= 64)
                        {
                            //出现可自动恢复错误
                            PrinterStatus = -1;
                        }
                        if (printerStatus2 >= 3)
                        {
                            //纸张将用尽
                            PrinterStatus = 2;
                        }
                        if (printerStatus2 >= 12)
                        {
                            //缺纸
                            PrinterStatus = -1;
                        }
                        if (PrinterStatus < 0)
                            stringMessage = "打印机状态异常";
                    }
                }
                if (ConnectStatus > 0 && PrinterStatus > 0) IsPrinterReady = true;
                else IsPrinterReady = false;
                SettingStatusBarInMainThread(IsPrinterReady);
                this.listBoxReceivedStatusMessage.Items.Add(stringMessage);
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
                ConnectStatus = -1;
                PrinterStatus = -1;
                IsPrinterReady = false;
            }
            finally
            {
                //线程继续运行
                PulseCheckTimeoutObject.Set();
            }
        }


        public void RestoreRadioButtonsInMainThread()
        {
            try
            {
                if (this.IsDisposed)
                    return;

                if (!this.InvokeRequired)
                {
                    //RestoreRadioButtons();
                    return;
                }
                //MethodInvoker 需要无参数的函数，所以使用匿名委托将带参数的函数转换为不带参数的委托
                this.Invoke(
                    new MethodInvoker(
                        delegate ()
                        {
                            //RestoreRadioButtons();
                        }
                    )
                );
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
        }

        /// <summary>
        /// 开始服务器心跳检查
        /// </summary>
        public void StartPulseCheck()
        {
            myTimerPulseCheck = new System.Threading.Timer(ProcessPulseCheck, "Processing timer event", 100, 6000);//2秒后第一次调用，每1秒调用一次  
        }


        /// <summary>
        /// 开始打印任务处理
        /// </summary>
        /// <param name="processInteval">处理时间间隔，每隔多少毫秒处理一次打印任务</param>
        public void StartTaskProcess(int processInteval=2000)
        {
            myTimerProcessTask = new System.Threading.Timer(ProcessPrintTask, "Processing timer event", 500, processInteval);//2秒后第一次调用，每1秒调用一次  
        }

        /// <summary>
        /// 将新增的打印任务添加到ReceivedTaskList列表中
        /// </summary>
        private int AddNewTaskToReceivedTaskList(ref List<PrintTaskV1d0> receivedTaskList)
        {
            int newTaskCount = 0;
            try
            {
                //当前已接收到打印任务中的任务序号的最大值
                long currTaskIndexMax = (receivedTaskList.Count > 0) ? (receivedTaskList.Max(x => x.task_index)) : 0;

                //服务器上的待打印任务数据表中的任务序号最大值
                var serverTaskList = GetPrintTaskFromServer(currTaskIndexMax);
                long serverTaskIndex = (serverTaskList.Count > 0) ? (serverTaskList.Max(x => x.task_index)) : 0;

                //如果服务器序号最大值大于已接收到的任务需要的最大值,则说明有新增打印任务
                if (serverTaskIndex > currTaskIndexMax)
                {
                    var newTastList = serverTaskList.FindAll(x => x.task_index > currTaskIndexMax);
                    newTaskCount = newTastList.Count;
                    receivedTaskList.AddRange(newTastList);
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            return newTaskCount;

        }
        /// <summary>
        /// 处理打印任务，
        /// </summary>
        private void ProcessPrintTask(object state)
        {
            try
            {
                //将数据表中新增任务添加到已接收打印任务列表
                int newTaskCount=AddNewTaskToReceivedTaskList(ref ReceivedTaskList);
                long taskIndexMax = ReceivedTaskList.Max(x => x.task_index);

                if (newTaskCount>0|| CurrTaskIndex< taskIndexMax)
                {
                    UpdateListBox(listBoxReceivedTask, ReceivedTaskList);
                    ////只有在打印机就绪时，再进行任务打印
                    //if (IsPrinterReady)
                    //{
                        PulseCheckTimeoutObject.Reset();
                        //每次处理打印任务之前，必须再连接一次打印机，同时进行一次心跳检测
                        SendPrinterPulseCheckCommand(null);

                    //只有在0.1秒内接收到心跳信号，才进行打印任务的处理
                    if (PulseCheckTimeoutObject.WaitOne(500, false))
                    {
                        if (IsPrinterReady)
                        {
                            lock (LockReceivedTaskList)
                            {
                                var records = ReceivedTaskList.FindAll(x => x.task_index > CurrTaskIndex);
                                if (records.Count > 0)
                                {
                                    //得到当前任务的序号
                                    CurrTaskIndex = records.Min(x => x.task_index);
                                    var currPrintTask = ReceivedTaskList.FirstOrDefault(x => x.task_index == CurrTaskIndex);
                                    SendPrintTaskToPrinter(currPrintTask);
                                }
                            }
                            //关闭连接
                            TcpConnectThread.IsDisconnected = false;
                        }
                        else
                        {
                            //关闭连接
                            TcpConnectThread.IsDisconnected = true;
                        }
                    }
                    else
                    {
                        //一旦超时，可任务打印机不可用
                        IsPrinterReady = false;
                        TcpConnectThread.IsDisconnected = true;
                    }
                    //}
                    
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            SettingStatusBarInMainThread(IsPrinterReady);
        }

        private void ProcessPulseCheck(object state)
        {
            //每次处理打印任务之前，必须再连接一次打印机，同时进行一次心跳检测
            try
            {

                PulseCheckTimeoutObject.Reset();
                SendPrinterPulseCheckCommand(null);
                //只有在0.1秒内接收到心跳信号，才进行打印任务的处理
                if (PulseCheckTimeoutObject.WaitOne(500, false))
                {
                    if (!IsPrinterReady)
                    {
                        //关闭连接
                        TcpConnectThread.IsDisconnected = true;
                    }
                    else TcpConnectThread.IsDisconnected = false;
                }
                else
                {
                    //一旦超时，通知线程，套接字已断开
                    IsPrinterReady = false;
                    TcpConnectThread.IsDisconnected = true;
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            SettingStatusBarInMainThread(IsPrinterReady);
        }
        /// <summary>
        /// 发送服务器心跳检测信号，如果与打印机未连接，则进行连接
        /// </summary>
        private bool SendPrinterPulseCheckCommand(object state)
        {
            bool result = false;
            try
            {
                if(PrinterTcpClient!=null&&PrinterTcpClient.Connected)
                {
                    //请求打印机发送进纸盒状态，作为心跳检测信号
                    result=SendRequstPaperStatusCommand();
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            return result;
        }
        private bool SendRequstPaperStatusCommand()
        {
            TmU220EscPosPrintFunctionV1d0 printer = new TmU220EscPosPrintFunctionV1d0(PrinterTcpClient);
            bool result = printer.SendByteCommand(PrinterCmdUtilsV1d0.transferPrinterStatus());
            return result;
        }
        public bool SendPrintTaskToPrinter(PrintTaskV1d0 printTask)
        {
            bool result = false;
            TmU220EscPosPrintFunctionV1d0 printer = new TmU220EscPosPrintFunctionV1d0(PrinterTcpClient);
            //进行排序
            printTask.PrintTaskItemList.OrderBy(x => x.print_sequence);
            foreach (var item in printTask.PrintTaskItemList)
            {
                result = printer.SendPrintTaskItemToPrinter(item);
            }
            return result;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            
        }
    }
}
